package org.jpush.utils;

import sun.net.util.IPAddressUtil;

public class IPRange
{
	private long startIP;
	private long endIP;
	private int ipType;
	
	public IPRange(String startIP, String endIP)
	{
		if (!isSameFormat(startIP, endIP))
		{
			throw new RuntimeException("Not same type of IP:" + startIP + "/" + endIP);
		}
		
		byte[] ipBytes = text2Numeric(startIP);
		this.ipType = ipBytes.length;
		this.startIP = numeric2Long(ipBytes);
		this.endIP = numeric2Long(text2Numeric(endIP));
	}
	
	public boolean isWithin(String ip)
	{     
        return (isWithin(text2Numeric(ip)));
	}
	
	public boolean isWithin(byte[] ipBytes)
	{
		if (ipBytes.length != ipType)
		{
			return false;
		}

    	long ipLong = numeric2Long(ipBytes);        
        return (ipLong <= endIP && ipLong >= startIP);
	}

	private static long numeric2Long(byte[] ipBytes)
	{
		long lRet = 0L;
		if (ipBytes.length == 4)
		{
			lRet = (ipBytes[3] & 0xFF) << 24
			     | (ipBytes[2] & 0xFF) << 16
			     | (ipBytes[1] & 0xFF) << 8
			     | (ipBytes[0] & 0xFF);
		}
		else if (ipBytes.length == 6)
		{
			lRet = (ipBytes[5] & 0xFF) << 40
		     | (ipBytes[4] & 0xFF) << 32
		     | (ipBytes[3] & 0xFF) << 24
		     | (ipBytes[2] & 0xFF) << 16
		     | (ipBytes[1] & 0xFF) << 8
		     | (ipBytes[0] & 0xFF);
		}
		else
		{
			throw new RuntimeException("Unknown IP format");
		}
		
		return lRet;
	}

	private static byte[] text2Numeric(String ip)
	{
		if (IPAddressUtil.isIPv4LiteralAddress(ip))
		{
			return IPAddressUtil.textToNumericFormatV4(ip);
		}
		else if (IPAddressUtil.isIPv6LiteralAddress(ip))
		{
			return IPAddressUtil.textToNumericFormatV6(ip);
		}
		else
		{
			throw new RuntimeException("Unknown IP format:" + ip);
		}
	}

	private static boolean isSameFormat(String ipStart, String ipEnd)
	{
		return (
				(IPAddressUtil.isIPv4LiteralAddress(ipStart)) && 
				(IPAddressUtil.isIPv4LiteralAddress(ipEnd))
			   ) || 
			   (
				(IPAddressUtil.isIPv6LiteralAddress(ipStart)) && 
				(IPAddressUtil.isIPv6LiteralAddress(ipEnd))
			   );
	}
}